﻿#region

using AspectCore.Configuration;
using AspectCore.DynamicProxy.Parameters;
using AspectCore.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Vin.Extension.Aop.Attributes.Parameter;
using Vin.Extension.Aop.Options;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Attributes;

#endregion

namespace Vin.Extension.Aop;

[Order(-10000)]
public class ExtensionEntry : IVinExtension
{
    public const string OptionKey = "VinAop";

    public void AddVinExtension(WebApplicationBuilder builder)
    {
        VinApp.AddInjectProvider(InjectProvider);

        // 注入代理
        builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
        builder.Services.ConfigureDynamicProxy(config =>
        {
            // config.EnableParameterAspect();
            // 修改为只有标记了 VinBaseParameterInterceptorAttribute 特性的方法才启用参数拦截
            config.EnableParameterAspect(methodInfo =>
            {
                return methodInfo.GetParameters().Any(parameter =>
                           parameter.IsDefined(typeof(VinBaseParameterInterceptorAttribute), true)) ||
                       VinAopExtension.EnableParameterAspectFilter?.Invoke(methodInfo) == true;
            });
            
            var aopOption = VinApp.Configuration.GetSection(OptionKey).Get<AopOption>() ?? new AopOption();

            foreach (var nameSpace in aopOption.AllIgnoreNamespaces)
            {
                config.NonAspectPredicates.AddNamespace(nameSpace);
            }

            foreach (var service in aopOption.IgnoreServices)
            {
                config.NonAspectPredicates.AddService(service);
            }

            foreach (var method in aopOption.IgnoreMethods)
            {
                config.NonAspectPredicates.AddMethod(method);
            }
        });
    }

    public void AddVinExtension(IServiceCollection services)
    {
    }

    public void UseVinExtension(WebApplication app)
    {
    }

    private List<InjectModel> InjectProvider(Type instanceType)
    {
        var injects = new List<InjectModel>();
        var baseType = instanceType.BaseType;
        while (baseType != null && baseType != typeof(object))
        {
            injects.AddRange(VinApp.DefaultInjectProvider(baseType));
            baseType = baseType.BaseType;
        }

        return injects.DistinctBy(m => m.Type).ToList();

        // if (instanceType.BaseType != null)
        // {
        //     return VinApp.DefaultInjectProvider(instanceType.BaseType);
        // }
        //
        // return new List<InjectModel>();
    }
}